﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using King.Engine;
using King.Engine.Components;
using King.Engine.Content;
using King.Engine.Core;
using King.Engine.GameObjects;

namespace BreacherCreature.Components
{
    public class LightCone : Component
    {

        #region Fields

        Texture2D _coneTex;
        Vector2 _textureCenter;
        float _rotationOffset = 0;

        #endregion

        #region Properties

        /// <summary>
        /// The color the light is drawn as
        /// </summary>
        public Color LightColor;

        /// <summary>
        /// The offset of the light cone when the parent is at a rotation of 0
        /// </summary>
        public Vector2 ParentOffset;

        /// <summary>
        /// The current location of the light cone based off of parent location and rotation
        /// </summary>
        public Vector2 Location
        {
            get {
                return Vector2.Transform(ParentOffset, Matrix.CreateRotationZ(Parent.Rotation)) + Parent.Location;
            }
        }

        /// <summary>
        /// The radius of the cone
        /// </summary>
        public float Radius
        {
            get { return _coneTex.Width / 2; }
        }
        
        double _fov;
        /// <summary>
        /// The angle in radians of the field of view
        /// </summary>
        public double FOV
        {
            get { return _fov; }
            set
            {
                _fov = value;

                UpdateFovTexture();
            }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Creates a light cone component for a game object
        /// </summary>
        /// <param name="FOV">Angle in radians</param>
        /// <param name="lightColor">Color to draw cone</param>
        /// <param name="offset">Offset of the cone from parent game object</param>
        public LightCone(double FOV, Color lightColor, Vector2 offset)
        {
            this.ParentOffset = offset;
            this.LightColor = lightColor;
            this.FOV = FOV;
        }

        #endregion

        #region Public Methods

        public override void Draw()
        {
            Screen.Draw(_coneTex, Location, null, Color.White, Parent.Rotation + _rotationOffset, _textureCenter, 1, SpriteEffects.None, 0);
        }

        /// <summary>
        /// Determines whether a point is inside the cone
        /// </summary>
        /// <param name="point">The point to be checked</param>
        /// <returns>Whether the cone contains the point</returns>
        public bool CollidesWith(Vector2 point)
        {
            float distanceFrom = Vector2.Distance(Location, point);

            if (distanceFrom > Radius)
                return false;

            Vector2 coneVector = Vector2.Transform(new Vector2(1, 0), Matrix.CreateRotationZ(Parent.Rotation));
            Vector2 queryVector = point - Location;
            queryVector.Normalize();

            double angleTo = Math.Acos(Vector2.Dot(coneVector, queryVector));

            return Math.Abs(angleTo) < FOV / 2;
        }

        /// <summary>
        /// Determines whether the center of a rectangle is inside the cone
        /// </summary>
        /// <param name="rect">The rect to be checked</param>
        /// <returns>Whether the cone contains the center of the rectangle</returns>
        public bool CollidesWith(Rectangle rect)
        {
            return CollidesWith(rect.CenterVector());
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Updates the light cone texture based on an updated field of view
        /// </summary>
        void UpdateFovTexture()
        {
            Texture2D baseCircle = ContentLoader.Get<Texture2D>("LightConeBaseCircle");
            _textureCenter = baseCircle.Center();
            int width = baseCircle.Width;
            int height = baseCircle.Height;
            double fovDiff = Math.PI - FOV;

            Vector2 center = new Vector2(width / 2, height / 2);
            float baseRotation = (float)Math.PI / 2 * 3;
            float halfAngle = (float)FOV / 2;

            GraphicsDevice device = King.Engine.Core.Game.GraphicDevice;
            RenderTarget2D target = new RenderTarget2D(device, width, height, false, SurfaceFormat.Color, DepthFormat.None);

            device.SetRenderTarget(target);
            device.Clear(Color.Transparent);
            SpriteBatch spriteBatch = new SpriteBatch(device);

            spriteBatch.Begin();

            spriteBatch.Draw(baseCircle, center, new Rectangle(0, 0, width, height / 2), Color.Black, baseRotation - halfAngle, center, 1.5f, SpriteEffects.None, 0);
            spriteBatch.Draw(baseCircle, center, new Rectangle(0, 0, width, height / 2), Color.Black, baseRotation + halfAngle, center, 1.5f, SpriteEffects.None, 0);

            spriteBatch.End();

            device.SetRenderTarget(null);

            Texture2D mask = (Texture2D)target;

            int textureSize = width * height;

            Color[] maskColor = new Color[textureSize];
            mask.GetData(maskColor);

            Color[] textureColor = new Color[textureSize];
            baseCircle.GetData(textureColor);

            for (int i = 0; i < textureSize; i++)
                if (maskColor[i].A > 0)
                    textureColor[i] = Color.Transparent;
                else if (textureColor[i].A > 0)
                    textureColor[i] = LightColor;

            _coneTex = new Texture2D(device, width, height);
            _coneTex.SetData(textureColor);
        }

        #endregion
    }
}
